/*
 * 使用STM32cubemax生成的HAL库，软件I2C的实现
 */

#include "i2c.h"
#include "tim.h"

void HAL_Delay_us(uint16_t us)
{
    uint16_t differ=0xffff-us-5;                    //设定定时器计数器起始值
    __HAL_TIM_SET_COUNTER(&htim4,differ);

    HAL_TIM_Base_Start(&htim4);                     //启动定时器
	while(differ<0xffff-6)                             //补偿，判断
	{
		differ=__HAL_TIM_GET_COUNTER(&htim4);             //查询计数器的计数值
	}
	HAL_TIM_Base_Stop(&htim4);
}

//i2c的开始信号
void i2c_start(){
	SDA_H();
	SCL_H();				//初始高电平
	HAL_Delay_us(100);		//延时
	SDA_L();						//SDA拉低
    HAL_Delay_us(100);		//延时
	SCL_H();				//初始高电平
	HAL_Delay_us(100);		//延时
}

//i2c的停止信号
void i2c_stop(){
	SCL_L();				//初始低电平
	SDA_L();

	HAL_Delay_us(100);
	SCL_H();
	
	HAL_Delay_us(100);
	SDA_H();
    HAL_Delay_us(100);
}

//等待应答信号
void i2c_waitack(){
	uint8_t waittime = 0;
    uint8_t rack = 0;

	SCL_L();  
	HAL_Delay_us(100);
    SDA_H();     		/* 主机释放SDA线(此时外部器件可以拉低SDA线) */
    HAL_Delay_us(100);
    SCL_H();      		/* SCL=1, 此时从机可以返回ACK */
    HAL_Delay_us(100);
    while (SDA_LEVEL() == 1)    /* 等待应答 */
    {
        waittime++;
        if (waittime > 250)
        {
            i2c_stop();
            rack = 1;
            break;
        }
    }
    SCL_L();     /* SCL=0, 结束ACK检查 */
    HAL_Delay_us(100);
}
//应答信号
void i2c_ack(void)
{
    SDA_L();     /* SCL 0 -> 1  时 SDA = 0,表示应答 */
    HAL_Delay_us(100);
    SCL_H();     /* 产生一个时钟 */
    HAL_Delay_us(100);
    SCL_L();
    HAL_Delay_us(100);
    SDA_H();    /* 主机释放SDA线 */
    HAL_Delay_us(100);
}

void i2c_nack(void)
{
    SDA_H();    /* SCL 0 -> 1  时 SDA = 1,表示不应答 */
    HAL_Delay_us(100);
    SCL_H();     /* 产生一个时钟 */
    HAL_Delay_us(100);
    SCL_L();
    HAL_Delay_us(100);
}

uint8_t iic_read_byte(uint8_t ack)
{
    uint8_t i, receive = 0;

    for (i = 0; i < 8; i++ )    /* 接收1个字节数据 */
    {
        receive <<= 1;  /* 高位先输出,所以先收到的数据位要左移 */
        SCL_H();
        HAL_Delay_us(100);

        if (SDA_LEVEL() == 1)
        {
            receive++;
        }
        SCL_L();
        HAL_Delay_us(100);
    }
    if (!ack)
    {
        i2c_nack();     /* 发送nACK */
    }else{
        i2c_ack();      /* 发送ACK */
    }
    return receive;
}

